<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>
  <meta http-equiv="Content-type" content="text/html; charset=utf-8" />

  <title>M:M relationship editor</title>

  <link rel="stylesheet" type="text/css" title="Default Style" href="../../style/tree/compat/style.css" media="screen" />
  <link rel="stylesheet" type="text/css" title="Default Style" href="../../style/button/default/style.css" media="screen" />

  <style type="text/css" id="demo-css">
    HTML
    {
      padding: 0;
      margin: 0;
      font-family: Tahoma, Verdana, sanf-serif;
      font-size: small;
    }
    BODY
    {
      padding: 0 10px;
      margin: 0;
    }

    .Basis-Tree
    {
      border: 1px solid #AAA;
      width: 300px;
      height: 400px;
      overflow: auto;
      overflow-y: scroll;
      overflow-x: hidden;
    }

    .ListContainer
    {
      float: left;
      margin-right: 10px;
    }
    .ListContainer .debug
    {
      height: 2em;
    }

    .Basis-ButtonPanel
    {
      padding-bottom: 4px;
      margin-left: -4px;
    }

    .form-content
    {
      overflow: hidden;
    }

    #MasterTree .Basis-Tree-Node A
    {
      padding-left: 5px;
      margin: 0;
      background: #A0C0DD !important;
        -moz-border-radius: 3px;
        -webkit-border-radius: 3px;
      border-radius: 3px;
    }
    #MasterTree .Basis-Tree-Node
    {
      float: left;
      margin: 0 0 2px 2px;
    }
    #MasterTree .Basis-Tree-Folder
    {
      clear: both;
      border-bottom: 1px solid #E0E0E0;
      cursor: pointer;
    }
    #MasterTree .Basis-Tree-Folder:hover
    {
      background: #EEE;
    }
    #MasterTree .Basis-Tree-Folder UL
    {
      padding-top: 2px;
      overflow: hidden;
    }
    #MasterTree .count
    {
      margin-left: 1ex;
      color: #AAA;
    }
    #MasterTree .selected
    {
      background: #D9E8FB !important;
    }

    #RelatedTree .Basis-Tree-NodeGroup-Content
    {
      display: none;
    }
    #RelatedTree .Basis-Tree-NodeGroup-Title
    {
      cursor: pointer;
      background: white;
      padding-bottom: 4px;
    }
    #RelatedTree .Basis-Tree-NodeGroup-Title:hover
    {
      background: #E0E0E8;
    }
    #RelatedTree .Basis-Tree-NodeGroup-Title INPUT
    {
      margin: 0 5px 0 0;
      padding: 0;
      position: relative;
      top: 2px;
    }
    #RelatedTree .selected .Basis-Tree-NodeGroup-Title
    {
      background: #CCC;
    }
  </style>
  <!--[if lt IE 7]>
  <style type="text/css">
    BODY
    {
      font-size: x-small;
    }
  </style>
  <![endif]-->

  <script type="text/javascript" src="../../basis.js"></script>
  <script type="text/javascript" src="../../data.js"></script>
  <script type="text/javascript" src="../../dom_wrapper.js"></script>
  <script type="text/javascript" src="../../entity.js"></script>
  <script type="text/javascript" src="../../tree.js"></script>
  <script type="text/javascript" src="../../button.js"></script>

  <script type="text/javascript" src="../demo.js"></script>
</head>

<body>
  <h1>M:M relationship editor</h1>

  <p id="demo-summary">
    ...
  </p>
  <div id="demo-description">
    <p>...</p>
  </div>

  <div id="demo-container"></div>

  <script id="demo-javascript" type="text/javascript">

    var Class = Basis.Class;
    var Event = Basis.Event;
    var DOM = Basis.DOM;

    var nsEntity = Basis.Entity;
    var nsTree = Basis.Controls.Tree;
    var nsButton = Basis.Controls.Button;
    
    // Определяем новый тип данных.
    var Field = new nsEntity.EntityType({
      // Необязательное поле, используется в основном для отладки.
      name: 'Field',

      // Определяем набор полей
      fields: {
        FieldId: nsEntity.IntId,
        Title: String
      }
    });

    // Определяем новый тип данных.
    var Property = new nsEntity.EntityType({
      // Необязательное поле, используется в основном для отладки.
      name: 'Property',

      // Определяем набор полей
      fields: {
        PropertyId: nsEntity.IntId,
        Title: String
      }
    });

    // Определяем новый тип данных.
    var Link = new Basis.Entity.EntityType({
      // Необязательное поле, используется в основном для отладки.
      name: 'Link',

      // Определяем набор полей
      fields: {
        LinkId: nsEntity.StringId,
        FieldId: Number,
        PropertyId: Number
      },

      groupings: {
        FieldId: Function.getter('info.FieldId'),
        PropertyId: Function.getter('info.PropertyId')
      }
    });

    Link.getGrouping('FieldId').destroyEmpty = false;
    Link.getGrouping('PropertyId').destroyEmpty = false;

    // Генерируем тестовый набор данных.
    for (var i = 1; i <= 10; i++)
    {
      Field({
        FieldId: i,
        Title: 'Field #' + i
      });
      Property({
        PropertyId: i,
        Title: 'Property #' + i
      });
    }

    for (var i = 0; i < 25; i++)
    {
      var fieldId = parseInt((i * 2347.56) % Field.all.itemCount) + 1;
      var propertyId = parseInt((i * 7263.23) % Property.all.itemCount) + 1;
      Link({
        LinkId: fieldId + '-' + propertyId,
        FieldId: fieldId,
        PropertyId: propertyId
      });
    }

    // Какой набор является главным
    var masterSet = 'Field';

    // Главное дерево - список полей
    var masterTree = new nsTree.Tree({
      id: 'MasterTree',

      // Определяем класс для дочерних узлов
      childClass: Class(nsTree.TreeFolder, {
        template: new Basis.Html.Template(
          '<li{element|selectedElement} class="Basis-Tree-Folder">' + 
            '<div{content} class="Tree-Node-Title Tree-Folder-Content">' + 
              '<div{expander} class="Basis-Tree-Expander"/>' + 
              '<a href="#">{titleText|[no title]}<span class="count">({countText|0})</span></a>' + 
            '</div>' + 
            '<ul{childNodesElement}/>' + 
          '</li>'
        ),

        collapsed: true,
        titleGetter: Function.getter('info.Title'),
        localSorting: Function.getter('delegate.getId()'),
        childClass: Class(nsTree.TreeNode, {
          titleGetter: function(node){
            return (masterSet == 'Field' ? Property.get(node.info.PropertyId) : Field.get(node.info.FieldId)).info.Title;
          },
          behaviour: {
            click: function(){
              if (this.parentNode)
                this.parentNode.select();
            }
          }
        }),
        behaviour: {
          childNodesModified: function(){
            this.countText.nodeValue = this.childNodes.length;
          },
          update: function(object, delta){
            this.inherit(object, delta);

            var rootDelegate = this.getRootDelegate();
            var idField = rootDelegate.entityType.idField;
            if (idField in delta)
            {
              var id = rootDelegate.getId();
              this.setCollection(id ? Link.getGrouping(idField).getGroup(id, true) : null);
            }
          }
        }
      }),

      collection: Field.all,

      // Определяем сортировку для дочерних узлов: сортируем по node.info.title.
      localSorting: 'delegate.getId()',

      // Задаем обработчик на событие изменения выборки (Selection).
      selection: {
        handlers: {
          change: function(){
            var selected = this.pick();
            relatedTree.setDelegate(selected);
            DOM.visibility(DOM.get('relatedTreeContainer'), selected);
          }
        }
      }
    });

    // Зависимое дерево - список свойств
    var RelatedTree = Class(nsTree.Tree, {
      className: 'RelatedTree',
      behaviour: {
        delegateChanged: function(object, oldDelegate){
          var rootDelegate = this.getRootDelegate();

          this.setCollection();
          if (this.delegate)
          {
            var idField = rootDelegate.entityType.idField;
            this.groupControl.setCollection(idField == 'FieldId' ? Property.all : Field.all);
            this.setCollection(Link.getGrouping(idField).getGroup(rootDelegate.getId(), true));
          }
        }
      },
      groupControlClass: Class(nsTree.TreeGroupControl, {
        className: 'RelatedTreeGroupControl',
        childClass: Class(nsTree.TreePartitionNode, {
          template: new Basis.Html.Template(
            '<li{element} class="Basis-Tree-NodeGroup">' + 
              '<div class="Basis-Tree-NodeGroup-Title"><input{checkbox} type="checkbox"/><span>{titleText}</span></div>' +
              '<ul{childNodesElement} class="Basis-Tree-NodeGroup-Content"/>' +
            '</li>'
          ),
          behaviour: {
            click: function(event){
              var rootDelegate = this.document.getRootDelegate();
              var idField = rootDelegate.entityType.idField;

              var field = idField == 'FieldId' ? rootDelegate : this.delegate;
              var property = idField == 'PropertyId' ? rootDelegate : this.delegate;

              var fieldId = field.getId();
              var propertyId = property.getId();
              var linkId = fieldId + '-' + propertyId;

              if (this.firstChild)
              {
                Link(linkId).destroy();
              }
              else
              {
                Link({
                  LinkId: fieldId + '-' + propertyId,
                  FieldId: fieldId,
                  PropertyId: propertyId
                });
              }
            },
            childNodesModified: function(){
              var isExists = !!this.firstChild;
              this.checkbox.checked = isExists;
              Basis.CSS.cssClass(this.element).bool('selected', isExists);
            }
          }
        })
      })
    });

    var relatedTree = new RelatedTree({
      id: 'RelatedTree',

      localGrouping: {
        //collection: Property.all,
        groupGetter: function(node){
          return masterSet == 'Field' ? Property.get(node.info.PropertyId) : Field.get(node.info.FieldId);
        },
        titleGetter: Function.getter('info.Title')
      },

      // Определяем сортировку для дочерних узлов: сортируем по node.info.title.
      localSorting: 'delegate.getId()'
    });

    // NOTE: для отладки - список всех связей
    var linksTree = new nsTree.Tree({
      // Определяем класс для дочерних узлов (описан выше)
      childClass: Class(nsTree.TreeNode, {
        titleGetter: function(node){
          var field = Field.get(node.info.FieldId);
          var property = Property.get(node.info.PropertyId);
          return (field ? field.info.Title : '[no field]') + ' <-> ' + (property ? property.info.Title : '[no property]');
        }
      }),

      collection: Link.all,
      localSorting: 'info.FieldId'
    });

    DOM.insert('demo-container', 
      DOM.createElement('#MainButtonPanel',
        DOM.createElement(
          {
            description: 'BUTTON',
            click: function(){

              masterButtonPanel.appendChild(
                relatedButtonPanel.replaceChild(
                  masterButtonPanel.lastChild,
                  relatedButtonPanel.lastChild
                )
              );

              if (masterSet == 'Field')
              {
                masterSet = 'Property';
                masterTree.setCollection(Property.all);
              }
              else
              {
                masterSet = 'Field';
                masterTree.setCollection(Field.all);
              }
            }
          },
          'Swap!'
        )
      )
    );

    var masterButtonPanel = new Basis.Controls.Button.ButtonPanel({
      childNodes: [
        {
          caption: 'Expand all',
          groupId: 1,
          handler: function(){
            masterTree.expandAll();
          }
        },
        {
          caption: 'Collapse all',
          groupId: 1,
          handler: function(){
            masterTree.collapseAll();
          }
        },
        {
          name: 'add',
          caption: 'Add field',
          handler: function(){
            var newId = parseInt(Math.random() * 1000000 + 10);
            Field({
              FieldId: newId,
              Title: 'Field #' + newId
            });
          }
        }
      ]
    });

    var relatedButtonPanel = new Basis.Controls.Button.ButtonPanel({
      childNodes: [
        {
          caption: 'Check all',
          groupId: 1,
          handler: function(){
            if (masterSet == 'Field')
            {
              var fieldId = relatedTree.info.FieldId;
              Property.all.getItems().forEach(function(property){
                var propertyId = property.info.PropertyId;
                Link({
                  LinkId: fieldId + '-' + propertyId,
                  FieldId: fieldId,
                  PropertyId: propertyId
                });
              });
            }
            else
            {
              var propertyId = relatedTree.info.PropertyId;
              Field.all.getItems().forEach(function(property){
                var fieldId = property.info.FieldId;
                Link({
                  LinkId: fieldId + '-' + propertyId,
                  FieldId: fieldId,
                  PropertyId: propertyId
                });
              });
            }
          }
        },
        {
          caption: 'Uncheck all',
          groupId: 1,
          handler: function(){
            var id = masterSet == 'Field' ? 'FieldId' : 'PropertyId';
            Link.getGrouping(id).getGroup(relatedTree.info[id]).getItems().forEach(function(link){
              link.destroy();
            });
          }
        },
        {
          name: 'add',
          caption: 'Add property',
          handler: function(){
            var newId = parseInt(Math.random() * 1000000 + 10);
            Property({
              PropertyId: newId,
              Title: 'Property #' + newId
            });
          }
        }
      ]
    });

    // Вставляем компоненты в документ
    DOM.insert('demo-container', [
      DOM.createElement('.ListContainer',
        masterButtonPanel.element,
        masterTree.element
      ),
      DOM.createElement(
        {
          description: '#relatedTreeContainer.ListContainer',
          css: {
            visibility: 'hidden'
          }
        },
        relatedButtonPanel.element,
        relatedTree.element
      ),
      DOM.createElement('.ListContainer',
        DOM.createElement('DIV.debug', 'Debug for (list of all links)'),
        linksTree.element
      )/*,
      groupsTree.element*/
    ]);

  </script>  
</body>

</html>
